package com.gw.booking.service;

import com.gw.booking.common.ApiException;
import com.gw.booking.common.Constant;
import com.gw.booking.common.MessageCode;
import com.gw.booking.common.Util;
import com.gw.booking.dto.PageDto;
import com.gw.booking.dto.backend.*;
import com.gw.booking.entity.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class UserService {
    @Autowired
    private SessionFactory sessionFactory;
    @Autowired
    private CaptchaService captchaService;
    @Autowired
    private LoginTokenService loginTokenService;
    @Autowired
    private PrivilegeService privilegeService;
    @Autowired
    RoleService roleService;
    @Autowired
    private LogService logService;
    @Autowired
    private CityService cityService;

    //为了商家取库存列表代码重用写的获取user方便获取商家id
    public User getUser(Integer userId) {
        Session session = sessionFactory.getCurrentSession();
        return (User) session.get(User.class, userId);
    }

    /**
     * 修改密码
     */
    public void txChangePassword(int userId, String remoteAddr, UserChangePasswordDto userChangePasswordDto) {
        Session session = sessionFactory.getCurrentSession();

        // 获取用户信息
        User user = getUser(session, userId);

        // 若用户不存在或者该用户已被删除
        if (user == null || !user.getDeleted().equals(Constant.FALSE)) {
            throw new ApiException(MessageCode.CODE_NO_USER);
        }

        // 验证用户输入的密码是否与原密码相同
        if (!StringUtils.equalsIgnoreCase(DigestUtils.md5Hex(userChangePasswordDto.getPassword()), user.getPassword())) {
            throw new ApiException(MessageCode.CODE_PASSWORD_ERROR);
        }

        // 修改密码
        user.setPassword(DigestUtils.md5Hex(userChangePasswordDto.getNewPassword()));
        user.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
        session.update(user);
        session.flush();

        logService.txAddLog(Logs.LogType.edit, userId, "修改密码");
    }

    /**
     * 取用户没有的权限列表
     */
    public List<Privilege> txGetUnachivedPrivileges(int userId) {
        Session session = sessionFactory.getCurrentSession();
        User user = assertUser(session, userId);
        // 根据user的userType获取角色对象
        Role role = roleService.assertRole(session, user.getRoleId());
        User.Type userType = User.Type.backend;

        if (StringUtils.isEmpty(role.getPrivilegeIds())) {
            return privilegeService.getUnachievedPrivilegeByIds(session, userType, null);
        }
        if (StringUtils.equals(Privilege.PRIVILEGE_ALL, role.getPrivilegeIds())) {
            return new ArrayList<>();
        }

        return privilegeService.getUnachievedPrivilegeByIds(session, userType
                , role.getPrivilegeIds().split(","));
    }

    /**
     * 登录
     */
    public LoginDtoOut txLogin(User.Type userType, LoginDto loginDto, String ip, HttpServletRequest request) {
        Session session = sessionFactory.getCurrentSession();

        // 验证图片验证码
        captchaService.checkCaptcha(request, loginDto.getCaptcha());

        User user = getUser(session, userType, loginDto.getName());
        City city = cityService.get(loginDto.getCityId());
        //用户名不存在/密码错误/城市id不为0且所选城市不匹配
        if (user == null
                || !StringUtils.equalsIgnoreCase(user.getPassword(), DigestUtils.md5Hex(loginDto.getPassword()))
                || (!user.getCityId().equals(Constant.USER_CITY_ID_ADMIN) && !user.getCityId().equals(loginDto.getCityId()))) {
            //手机或密码错误
            throw new ApiException(MessageCode.CODE_LOGIN_ERROR);
        }

        LoginToken loginToken = loginTokenService.txAddLoginToken(session, userType.name(), user.getId(), ip, loginDto.getCityId());

        Role role = roleService.getRole(session, user.getRoleId());

        // 记录登录时间
        user.setLastLoginTime(user.getLoginTime());
        user.setLoginTime(new Timestamp(System.currentTimeMillis()));
        session.update(user);
        session.flush();

        logService.txAddLog(Logs.LogType.login, loginToken.getUserId(), "登陆");
        return new LoginDtoOut(user.getId(), loginToken.getToken(), role.getPrivilegeIds(), user.getName(),
                city.getId(), city.getName(), city.getNameC());
    }


    /**
     * 确认用户名唯一
     */
    private void assertUniqueName(Session session, String name) {
        long count = (Long) session.createQuery("select count(*) from User" +
                " 	where name = :name")
                .setParameter("name", name)
                .uniqueResult();

        if (count > 0) {
            throw new ApiException(MessageCode.CODE_USERNAME_EXIST);
        }
    }

    /**
     * 确认用户信息
     */
    public User assertUser(Session session, Integer userId) {
        User user = getUser(session, userId);

        if (user == null) {
            throw new ApiException(MessageCode.CODE_NO_USER);
        }

        return user;
    }

    /**
     * 获取日志查询列表该页显示的项和数量
     */
    public PageDto<Object> getLogDetail(Session session, String operateType,
                                        String userName, String startDateStr, String endDateStr, int page, int size) {

        Date startDate = Util.parseStartDate(startDateStr);
        Date endDate = Util.parseEndDate(endDateStr);

        StringBuffer hqlCondition = new StringBuffer();
        StringBuffer hqlFlowColumns = new StringBuffer();
        StringBuffer hqlFlowCount = new StringBuffer();

        //记录数
        hqlFlowCount.append("select count(*)");

        // 查询字段
        hqlFlowColumns.append(" select ");
        hqlFlowColumns.append(" date_format(log.created_at,'%Y/%m/%d %H:%i:%s') createdAt, ");
        hqlFlowColumns.append(" log.user_name userName, log.operate_type operateType, ");
        hqlFlowColumns.append(" log.operate_content operateContent ");

        //查询条件
        hqlCondition.append(" from fl_log log ");
        hqlCondition.append(" where 1 = 1 ");

        if (operateType != null) {
            hqlCondition.append(" and log.operate_type = :operateType ");
        }

        if (userName != null) {
            hqlCondition.append(" and log.user_name = :userName ");
        }

        if (startDate != null) {
            hqlCondition.append(" and log.created_at >= :startDate ");
        }

        if (endDate != null) {
            hqlCondition.append(" and log.created_at < :endDate ");
        }

        hqlCondition.append(" order by log.created_at desc");

        Query queryCounts = session.createSQLQuery(hqlFlowCount.toString() + hqlCondition.toString());

        if (operateType != null) {
            queryCounts.setParameter("operateType", operateType);
        }

        if (userName != null) {
            queryCounts.setParameter("userName", userName);
        }

        if (startDate != null) {
            queryCounts.setParameter("startDate", startDate);
        }

        if (endDate != null) {
            queryCounts.setParameter("endDate", endDate);
        }

        BigInteger counts = (BigInteger) queryCounts.uniqueResult();

        //如果有数据
        if (counts.intValue() > 0) {
            Query query = session.createSQLQuery(hqlFlowColumns.toString() + hqlCondition.toString());

            if (operateType != null) {
                query.setParameter("operateType", operateType);
            }

            if (userName != null) {
                query.setParameter("userName", userName);
            }

            if (startDate != null) {
                query.setParameter("startDate", startDate);
            }

            if (endDate != null) {
                query.setParameter("endDate", endDate);
            }

            List<Object> items = query.setFirstResult(Util.calFirst(page, size)).setMaxResults(size).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();

            return new PageDto<Object>(page, size, counts.longValue(), items);

        }

        return new PageDto<Object>(page, size, counts.longValue(), null);
    }

    /**
     * 取得用户信息
     */
    public User getUser(Session session, int userId) {
        return (User) session.get(User.class, userId);
    }

    /**
     * 取得用户信息
     */
    private User getUser(Session session, User.Type userType, String name) {
        return (User) session.createCriteria(User.class).add(Restrictions.eq("name", name))
                .uniqueResult();
    }

    /**
     * 获取日志查询列表该页显示的项和数量
     */
    public PageDto<Object> getUserDetail(Session session, int page, int size) {

        StringBuffer hqlCondition = new StringBuffer();
        StringBuffer hqlFlowColumns = new StringBuffer();
        StringBuffer hqlFlowCount = new StringBuffer();

        //记录数
        hqlFlowCount.append("select count(*)");

        // 查询字段
        hqlFlowColumns.append(" select ");
        hqlFlowColumns.append(" user.id id, user.name name, role.role_name roleName, ");
        hqlFlowColumns.append(" user.mobile mobile ");


        //查询条件
        hqlCondition.append(" from fl_user user ");
        hqlCondition.append(" left join fl_role role on role.id = user.role_id ");
        hqlCondition.append(" where user.deleted = 0 ");

        Query queryCounts = session.createSQLQuery(hqlFlowCount.toString() + hqlCondition.toString());


        BigInteger counts = (BigInteger) queryCounts.uniqueResult();

        //如果有数据
        if (counts.intValue() > 0) {
            Query query = session.createSQLQuery(hqlFlowColumns.toString() + hqlCondition.toString());

            List<Object> items = query.setFirstResult(Util.calFirst(page, size)).setMaxResults(size).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list();

            return new PageDto<Object>(page, size, counts.longValue(), items);
        }

        return null;

    }


    /**
     * 取用户名称
     *
     * @param userId
     * @return
     */
    public String getUserName(Session session, Integer userId) {
        if (userId == null) {
            return null;
        }

        User user = getUser(session, userId);

        if (user == null) {
            return null;
        }

        return user.getName();
    }

    /**
     * 确认某字段值【手机号:mobile, 员工用户名：name】是否已存在
     */
    public void sureUserColumnValue(Session session, String columnName, String columnValue) {
        StringBuffer hqlCondition = new StringBuffer();
        hqlCondition.append(" from User ");
        if ("mobile".equals(columnName)) {
            hqlCondition.append(" where mobile = :value ");

            Query query = session.createQuery(hqlCondition.toString()).setParameter("value", columnValue);
            List list = query.list();
            if (list.size() != 0) {
                throw new ApiException(MessageCode.CODE_MOBILE_EXIST);
            }
        }

        if ("name".equals(columnName)) {
            hqlCondition.append(" where name = :value ");

            Query query = session.createQuery(hqlCondition.toString()).setParameter("value", columnValue);
            List list = query.list();
            if (list.size() != 0) {
                throw new ApiException(MessageCode.CODE_USERNAME_EXIST);
            }
        }

    }

    /**
     * 添加用户
     *
     * @param loginToken
     * @param userAddDto
     * @param userId
     */
    public void txAdd(LoginToken loginToken, UserAddDto userAddDto, Integer userId) {
        Session session = sessionFactory.getCurrentSession();
        // 确认员工用户名唯一性，是否已存在
        sureUserColumnValue(session, "name", userAddDto.getName());
        User user = new User();
        user.setName(userAddDto.getName());
        user.setUserName(userAddDto.getUserName());
        user.setRoleId(Constant.ROLE_ID_ADMIN);
        user.setPassword(DigestUtils.md5Hex(userAddDto.getPassword()));
        user.setDeleted(Constant.FALSE);
        user.setCreatedAt(new Timestamp(System.currentTimeMillis()));
        user.setCityId(userAddDto.getCityId());
        session.save(user);
        session.flush();

        logService.txAddLog(Logs.LogType.add, loginToken.getUserId(), "新增用户：" + user.getId());
    }

    /**
     * 删除用户
     */
    public void txDelete(LoginToken loginToken, Integer userId) {
        Session session = sessionFactory.getCurrentSession();
        User user = getUser(session, userId);
        // 若用户不存在或者该用户已删除
        if (user == null) {
            throw new ApiException(MessageCode.CODE_NO_USER);
        }
//        user.setDeleted(Constant.TRUE);
//        user.setUpdatedAt(new Timestamp(System.currentTimeMillis()));
        session.delete(user);
        logService.txAddLog(Logs.LogType.delete, loginToken.getUserId(), "用户删除：" + user.getName() + "用户信息删除");
    }

    /**
     * 编辑用户
     */
    public void txUpdate(LoginToken loginToken, UserUptDto userUptDto)
            throws IllegalAccessException, InvocationTargetException {
        Session session = sessionFactory.getCurrentSession();
        User user = getUser(session, userUptDto.getId());
        if (user == null) {
            throw new ApiException(MessageCode.CODE_NO_USER);
        }
        user.setUserName(userUptDto.getUserName());
        session.update(user);
        session.flush();

        logService.txAddLog(Logs.LogType.edit, loginToken.getUserId(), "用户信息修改：" + userUptDto.getId());
    }

    /**
     * 取用户列表
     */
    public PageDto<UserListDtoOut> txGetUsers(LoginToken loginToken, Integer page, Integer size) {
        Session session = sessionFactory.getCurrentSession();
        Long total = (Long) session.createQuery("select count(*) from User").uniqueResult();
        String sql = "select user.id,user.name,user.user_name as userName,user.created_at as createdAt,user.deleted" +
                "   ,user.city_id as cityId,city.name as cityName,city.name_c as cityNameC" +
                " from user user left join city city on user.city_id = city.id";
        List<UserListDtoOut> userListDtoOuts = session.createSQLQuery(sql)
                .setFirstResult(Util.calFirst(page, size))
                .setMaxResults(size)
                .setResultTransformer(Transformers.aliasToBean(UserListDtoOut.class))
                .list();
        return new PageDto<>(page, size, total, userListDtoOuts);
    }
}
